/**
 * 创建时间： 2017年5月6日
 *
 * @Copyright 武汉雷软科技有限公司
 */
package com.lrkj.framework.constant.listener;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.support.WebApplicationContextUtils;

import com.alibaba.fastjson.JSON;
import com.lrkj.framework.constant.annotation.NotMapping;

/**
 * <pre>
 * 创建人： 郭亮
 * 类描述：
 * 版本号：0.0.1
 * 修改人：
 * 修改时间：
 * 修改内容：
 * </pre>
 */
public class ConstantListener implements ServletContextListener {
    private final static Logger LOG = LoggerFactory.getLogger(ConstantListener.class);

    /**
     * 常量属性
     */
    @Autowired
    private ConstantProperties constantProperties;

    /*
     * (non-Javadoc)
     * 
     * @see
     * javax.servlet.ServletContextListener#contextInitialized(javax.servlet.
     * ServletContextEvent)
     */
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        ServletContext servletContext = sce.getServletContext();
        WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext).getAutowireCapableBeanFactory()
                .autowireBean(this);
        try {
            // 取得所有常量类 解析并加载到Application 并拼接常量JS
            List<Class<?>> classes = constantProperties.getClasses();
            Class<?>[] allClass = classes.toArray(new Class<?>[classes.size()]);
            StringBuilder sb = new StringBuilder();
            sb.append("(function(window) {");
            for (Class<?> cls : allClass) {
                Map<String, Object> map = new HashMap<>();
                parseClass(cls, servletContext, true, map);
                String clsName = cls.getSimpleName();
                LOG.debug("Scan class: {} ResultMap: {}", clsName, map);
                sb.append("window.").append(clsName).append("=").append(JSON.toJSONString(map)).append(";");
            }
            sb.append("})(window);");
            String content = sb.toString();
            LOG.debug("Constant JS : {}", content);
            constantProperties.setContent(content);
        } catch (Exception e) {
            LOG.error("请检查常量类配置是否正确", e);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see javax.servlet.ServletContextListener#contextDestroyed(javax.servlet.
     * ServletContextEvent)
     */
    @Override
    public void contextDestroyed(ServletContextEvent sce) {

    }

    /**
     * 解析常量
     *
     * @param classes
     *            类集合
     * @param servletContext
     *            servlet环境
     * @param isFirst
     *            是否顶级
     * @param next
     *            对象
     * @throws Exception
     *             异常
     */
    private void parseClass(Class<?> classes, ServletContext servletContext, boolean isFirst, Map<String, Object> next)
            throws Exception {
        if (isFirst) {
            Field[] fields = classes.getFields();
            parseField(next, fields);
            servletContext.setAttribute(classes.getSimpleName(), next);
            parseClass(classes, servletContext, false, next);
        } else {
            for (Class<?> cls : classes.getClasses()) {
                Map<String, Object> map = new HashMap<>();
                Field[] fields = cls.getFields();
                parseField(map, fields);
                next.put(cls.getSimpleName(), map);
                parseClass(cls, servletContext, false, map);
            }
        }
    }

    /**
     * 解析属性
     *
     * @param map
     *            集合
     * @param fields
     *            属性
     * @throws IllegalAccessException
     *             异常
     */
    private void parseField(Map<String, Object> map, Field[] fields) throws IllegalAccessException {
        for (Field field : fields) {
            boolean isStatic = Modifier.isStatic(field.getModifiers());
            if (isStatic && !field.isAnnotationPresent(NotMapping.class)) {
                Object value = field.get(null);
                map.put(field.getName(), value);
            }
        }
    }
}
